//        myD3D.cpp
//-------------------------
// Name:    Richard Lindholm
// Pno:        850629****
// Created: 06/08/28 12:57
//-------------------------
//

//-------------------------
// INCLUDE ETC

#include <iostream>
#include <fstream>
#include "myD3D.h"

using namespace std;


//-------------------------
// FUNCTIONS
RenderData::RenderData(int _Texture, D3DXVECTOR3 _TexPos, D3DCOLOR _TexColor, RENDERTYPE _TexType, RECT _TexSrc){

    Texture = _Texture;
    TexPos = _TexPos;
    TexColor = _TexColor;
    TexType = _TexType;
    TexSrc.bottom = _TexSrc.bottom;
    TexSrc.left = _TexSrc.left;
    TexSrc.right = _TexSrc.right;
    TexSrc.top = _TexSrc.top;
}


myD3D::myD3D( HWND hwnd, HINSTANCE hinstance ){ 

    startD3D( hwnd, hinstance );
    m_hwnd = hwnd;
    m_debugInfo = true;
}

bool myD3D::startD3D( HWND hwnd, HINSTANCE hinstance ){ // Init Direct3D

    // set some variables
    m_font = 0; // set font to zero
    m_sprite = 0; // set sprite to zero
    m_d3d = Direct3DCreate9( D3D_SDK_VERSION ); // d3d version


    // if m_d3d fails.. return false
    if ( !m_d3d ){

        MessageBoxA( 0, "Couldn't start Direct3D!", "Error", MB_OK | MB_ICONWARNING );
        return false;
    }

    // make a d3d present parameter and zero it
    D3DPRESENT_PARAMETERS d3dPP;
    ZeroMemory( &d3dPP, sizeof( d3dPP ) );


    //if ( MessageBoxA( hwnd, "Run in fullscreen?", "Choose your option", MB_YESNO | MB_ICONQUESTION ) == IDYES )
    //    m_bFullscreen = true;
    //else
        m_bFullscreen = false;

    // set d3d present parameters
    d3dPP.Windowed = !m_bFullscreen;
    d3dPP.SwapEffect = D3DSWAPEFFECT_DISCARD;
    d3dPP.BackBufferFormat = D3DFMT_X8R8G8B8;
    d3dPP.AutoDepthStencilFormat = D3DFMT_D24S8;
    d3dPP.EnableAutoDepthStencil = true;
    d3dPP.BackBufferHeight = 450;
    d3dPP.BackBufferWidth = 600;


    HRESULT hr;

    // create device
    hr = m_d3d->CreateDevice(
        D3DADAPTER_DEFAULT,
        D3DDEVTYPE_HAL,
        hwnd,
        D3DCREATE_SOFTWARE_VERTEXPROCESSING,
        &d3dPP,
        &m_device );


    // if CreateDevice failed quit program
    if ( FAILED( hr ) ){

        MessageBoxA( 0, "m_d3d->CreateDevice Failed!", "Error", MB_OK | MB_ICONWARNING );

        endD3D();
        return false;
    }

    // create font
    hr = D3DXCreateFont( m_device,                        // Device
                         24,                            // Height
                         0,                                // Width
                         FW_BOLD,                        // Weight
                         1,                                // MipLevels, 0 = autogen mipmaps
                         FALSE,                            // Italic
                         DEFAULT_CHARSET,                // CharSet
                         OUT_DEFAULT_PRECIS,            // OutputPrecision
                         DEFAULT_QUALITY,                // Quality
                         DEFAULT_PITCH | FF_DONTCARE,    // PitchAndFamily
                         m_strFont,                        // pFaceName
                         &m_font );                        // ppFont

    // if D3DXCreateFont failed quit program
    if ( FAILED( hr ) ){

        MessageBoxA( 0, "D3DXCreateFont Failed!", "Error", MB_OK | MB_ICONWARNING );

        endD3D();
        return false;
    }


    hr = D3DXCreateSprite( m_device, &m_sprite );

    // if D3DXCreateSprite failed quit program
    if ( FAILED( hr ) ){

        MessageBoxA( 0, "D3DXCreateSprite Failed!", "Error", MB_OK | MB_ICONWARNING );
        
        endD3D();
        return false;
    }

    return true;
}

void myD3D::endD3D(){ // shutdown Direct3D

    if (m_texList.size() != 0)
    {
        for ( int i = 0; i < (int)m_texList.size(); i++ )
        {
            m_texList[i]->Release();
        }
        m_texList.clear();
    }

    // release sprite if possible
    if ( m_sprite ){

        m_sprite->Release();
        m_sprite = 0;
    }

    // release font if possible
    if ( m_font ){

        m_font->Release();
        m_font = 0;
    }

    // if m_device exists, release and zero it
    if ( m_device ){

        m_device->Release();
        m_device = 0;
    }

    // if m_d3d exists, release and zero it
    if ( m_d3d ){

        m_d3d->Release();
        m_d3d = 0;
    }
}



void myD3D::render(){ // prints whats need to be printed

    // needed for debug text
    RECT rc;
    

    // clear what need to be cleared
    m_device->Clear( 0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB( 0,0,0 ), 1.0f, 0 );

    // begin render
    m_device->BeginScene();


        m_sprite->Begin( D3DXSPRITE_ALPHABLEND );

        //---------------------------------------------------------------------------
        // draw textures

        for ( int i = 0; i < (int)m_RenderListLow.size(); i++ ){

            if ( m_RenderListLow[i].TexType == TYPE_SPRITE )
                m_sprite->Draw( m_texList[m_RenderListLow[i].Texture], NULL, NULL, &m_RenderListLow[i].TexPos, m_RenderListLow[i].TexColor );
            else if ( m_RenderListLow[i].TexType == TYPE_TILE )
                m_sprite->Draw( m_texList[m_RenderListLow[i].Texture], &m_RenderListLow[i].TexSrc, NULL, &m_RenderListLow[i].TexPos, m_RenderListLow[i].TexColor );
        }
        for ( int i = 0; i < (int)m_RenderListMid.size(); i++ ){

            if ( m_RenderListMid[i].TexType == TYPE_SPRITE )
                m_sprite->Draw( m_texList[m_RenderListMid[i].Texture], NULL, NULL, &m_RenderListMid[i].TexPos, m_RenderListMid[i].TexColor );
            else if ( m_RenderListMid[i].TexType == TYPE_TILE )
                m_sprite->Draw( m_texList[m_RenderListMid[i].Texture], &m_RenderListMid[i].TexSrc, NULL, &m_RenderListMid[i].TexPos, m_RenderListMid[i].TexColor );
        }
        for ( int i = 0; i < (int)m_RenderListHig.size(); i++ ){

            if ( m_RenderListHig[i].TexType == TYPE_SPRITE )
                m_sprite->Draw( m_texList[m_RenderListHig[i].Texture], NULL, NULL, &m_RenderListHig[i].TexPos, m_RenderListHig[i].TexColor );
            else if ( m_RenderListHig[i].TexType == TYPE_TILE )
                m_sprite->Draw( m_texList[m_RenderListHig[i].Texture], &m_RenderListHig[i].TexSrc, NULL, &m_RenderListHig[i].TexPos, m_RenderListHig[i].TexColor );
        }        
        for ( int i = 0; i < (int)m_RenderListTop.size(); i++ ){

            if ( m_RenderListTop[i].TexType == TYPE_SPRITE )
                m_sprite->Draw( m_texList[m_RenderListTop[i].Texture], NULL, NULL, &m_RenderListTop[i].TexPos, m_RenderListTop[i].TexColor );
            else if ( m_RenderListTop[i].TexType == TYPE_TILE )
                m_sprite->Draw( m_texList[m_RenderListTop[i].Texture], &m_RenderListTop[i].TexSrc, NULL, &m_RenderListTop[i].TexPos, m_RenderListTop[i].TexColor );
        }


        m_sprite->End();

        //---------------------------------------------------------------------------

        for ( int i = 0; i < (int)m_TextBuffer.size(); i++ ){

            SetRect( &rc, m_TextBuffer[i].xPos, m_TextBuffer[i].yPos, 0, 0 );
            m_font->DrawTextA( NULL, m_TextBuffer[i].text.c_str(), -1, &rc, DT_NOCLIP, m_TextBuffer[i].color );
        }

        m_TextBuffer.clear();

        m_sprite->Begin( D3DXSPRITE_ALPHABLEND );

        // mouse is rendered last.. its always on top
        for ( int i = 0; i < (int)m_RenderListMouse.size(); i++ ){

            if ( m_RenderListMouse[i].TexType == TYPE_SPRITE )
                m_sprite->Draw( m_texList[m_RenderListMouse[i].Texture], NULL, NULL, &m_RenderListMouse[i].TexPos, m_RenderListMouse[i].TexColor );
            else if ( m_RenderListMouse[i].TexType == TYPE_TILE )
                m_sprite->Draw( m_texList[m_RenderListMouse[i].Texture], &m_RenderListMouse[i].TexSrc, NULL, &m_RenderListMouse[i].TexPos, m_RenderListMouse[i].TexColor );
        }

        m_sprite->End();

    // render done, end scene
    m_device->EndScene();

    // present
    m_device->Present( 0,0,0,0 );
}



int myD3D::AddTextureToList( char* filename ){

    LPDIRECT3DTEXTURE9 texture;
    D3DXCreateTextureFromFileExA( m_device, filename, D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT, D3DUSAGE_RENDERTARGET, D3DFMT_UNKNOWN, D3DPOOL_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, 0, 0, &texture );
    m_texList.push_back( texture );
    return (int)m_texList.size() - 1;
}

int myD3D::AddEmptyTextureToList( UINT texWidth, UINT texHeight ){

    LPDIRECT3DTEXTURE9 texture;
    //D3DXCreateTexture( m_device, texWidth, texHeight, 4, );
    HRESULT hr;
    hr = D3DXCreateTexture( m_device, texWidth, texHeight, 1, D3DX_DEFAULT, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &texture );
    if(FAILED(hr))
    {
        return -1;
    }

    m_texList.push_back( texture );
    return (int)m_texList.size() - 1;
}

void myD3D::AddToRenderList( RenderData data, RENDERPRIO prio ){

    if (data.Texture >= (int)m_texList.size())
    {
        if (m_texList.size() > 0)
        {
            data.Texture = 0;
        }
        else return;
    }
    if ( prio == LOW_PRIO )
        m_RenderListLow.push_back( data );
    else if ( prio == MID_PRIO )
        m_RenderListMid.push_back( data );
    else if ( prio == HIG_PRIO )
        m_RenderListHig.push_back( data );
    else if ( prio == TOP_PRIO )
        m_RenderListTop.push_back( data );
    else if ( prio == MOUSE_PRIO )
        m_RenderListMouse.push_back( data );
}

void myD3D::PlotPixel( UINT *video_buffer, UINT pitch, UINT x, UINT y, UINT r, UINT g, UINT b ){

    UINT pixel = D3DCOLOR_XRGB( r,g,b );

    video_buffer[ x + y * pitch ] = pixel;
}
//void Draw::plotPixel( UINT *video_buffer, UINT pitch, UINT x, UINT y, UINT r, UINT g, UINT b ){
//
//    UINT pixel = _RGB32( 0,r,g,b );
//
//    video_buffer[ x + y * pitch ] = pixel;
//}

void myD3D::ClearRenderList(){

    if ( m_RenderListLow.size() > 0 )
        m_RenderListLow.clear();

    if ( m_RenderListMid.size() > 0 )
        m_RenderListMid.clear();

    if ( m_RenderListHig.size() > 0 )
        m_RenderListHig.clear();

    if ( m_RenderListTop.size() > 0 )
        m_RenderListTop.clear();

    if ( m_RenderListMouse.size() > 0 )
        m_RenderListMouse.clear();
}

void myD3D::PrintText( int xPos, int yPos, const char *text, ... ){
        
    char *bffr = new char;
    va_list ap;

    if (text == NULL)
        return;

    va_start(ap, text);
    vsprintf(bffr, text, ap);
    va_end(ap);

    m_TextBuffer.push_back( TextData( bffr, xPos, yPos, m_textColor ) );
}